import { ElMessage, ElMessageBox } from "element-plus";
import $ from "jquery";
import * as math from 'mathjs';
import { evaluate } from 'mathjs';
import katex from 'katex';


const stGsW = {
    Subsystem: {
        children: ['From', 'Goto', 'In', 'Out', 'Subsystem']
    },
    Control: {
        children: ['Acc_Control', 'Filter_1st', 'Filter_2nd',
            'GainSchedule', 'Integrator', 'PID', 'TransferFcn']
    },
    Extend: {
        children: ['DllModel', 'FMU_Model']
    },
    Input: {
        children: ['Constant', 'SineWave', 'Step']
    },
    Math: {
        children: ['Abs', 'DeadZone', 'Delay', 'Gain', 'Lookup_1D',
            'Math', 'MinMax', 'Product', 'RelationalOperator',
            // 'RalationalOperator',
            'RateLimiter', 'Saturation', 'Sign', 'Sqrt', 'Sum']
    },
    Output: {
        children: ['Scope']
    },
    SignalRouting: {
        children: ['Demux', 'ManualSwitch', 'Mux', 'Switch']
    },
}

// const stGsW = {
//     Subsystem: {
//         // height: '300px',
//         children: ['Subsystem']
//     },
//     CustomSubsystem: {
//         // height: '300px',
//     },
//     'Commonly Used Blocks': {
//         // height: '300px',
//         children: [
//             'Constant', 'Delay', 'Demux', 'Gain', 'Integrator',
//             'Mux', 'Product', 'Relational\nOperator', 'Saturation',
//             'Scope', 'Sum', 'Switch'
//         ]
//     },
//     Continuous: {
//         // height: '300px',
//         children: ['Integrator', 'PID Controller', 'TransferFcn']
//     },
//     Discontinuities: {
//         // height: '300px',
//         children: ['Dead Zone', 'Rate Limiter', 'Saturation']
//     },
//     Discrete: {
//         // height: '300px',
//         children: ['Delay', 'Filter_1st', 'Filter_2nd', 'PID Controller']
//     },
//     // Example: {
//     //     // height: '300px',
//     //     children: [
//     //         'Formula', 'Pixmap', 'PixmapChangeDBC', 'PixmapChangedCB',
//     //         'PortChange', 'Text'
//     //     ]
//     // },
//     Input: {
//         // height: '100px',
//         children: ['Constant', 'SineWave', 'Step', 'DLL', 'FMU']
//     },
//     'Lookup Tables': {
//         // height: '100px',
//         children: ['1-D Lookup\nTable']
//     },
//     Math: {
//         // height: '750px',
//         children: [
//             'Abs', 'Constant', 'Delay', 'Demux', 'Filter_2nd',
//             'FromSpreadsheet', 'Gain', 'GlobalVar', 'Integrator',
//             'ManualSwitch', 'Math', 'MinMax', 'Mux', 'Product',
//             'Relational\nOperator', 'Saturation', 'Scope', 'Sign',
//             'SineWave', 'Sqrt', 'Step', 'Sum', 'Switch', 'temp',
//             'Dead Zone', 'MathFunction', 'Rate Limiter',
//         ]
//     },
//     'Math Operations': {
//         // height: '750px',
//         children: [
//             'Abs', 'FromSpreadsheet', 'Gain', 'GlobalVar', 'ManualSwitch',
//             'MAthFunction', 'MinMax', 'Product', 'Sign', 'Sqrt', 'Sum',
//             'temp',
//         ]
//     },
//     Output: {
//         // height: '100px',
//         children: ['Scope', 'GlobalVar']
//     },
//     SignalRouting: {
//         // height: '300px',
//         children: ['Demux', 'Mux', 'Switch', 'ManualSwitch']
//     },
//     Sourece: {
//         // height: '300px',
//         children: ['Constant', 'SineWave', 'Step']
//     },
//     Control: {
//         // height: '300px',
//         children: ['PID Controller', 'Gain', 'Integrator', 'TransferFcn', 'Filter_1st', 'Filter_2nd']
//     },
//     Extend: {
//         // height: '300px',
//         children: ['DLL', 'FMU', 'From Spreadsheet']
//     },
// }

const keywordObj = {
    e: { reg: /(?<!\w)e(?!\w)/gi, value: math.e },
    i: { reg: /(?<!\w)i(?!\w)/gi, value: "0.0000 + 1.0000i" },
    Inf: { reg: /(?<!\w)inf(?!\w)/gi, value: 'Infinity' },

    pi: { reg: /(?<!\w)pi(?!\w)/gi, value: math.pi },


    sqrt: {
        reg: /(?<!\w)sqrt\([\+\-*/.()^\d]+\)(?!\w)/gi,
        fn: e => math.sqrt(e)
    },
    log: {
        reg: /(?<!\w)log\([\+\-*/.()^\d]+\)(?!\w)/gi,
        fn: e => math.log(e)
    },
    exp: {
        reg: /(?<!\w)exp\([\+\-*/.()^\d]+\)(?!\w)/gi,
        fn: e => math.exp(e)
    },
    fabs: {
        reg: /(?<!\w)fabs\([\+\-*/.()^\d]+\)(?!\w)/gi,
        // reg: /(?<!\w)fabs\((\+|-)?[\d]+\)(?!\w)/gi,
        fn: e => math.abs(e)
    },
    sin: {
        reg: /(?<!\w)sin\([\+\-*/.()^\d]+\)(?!\w)/gi,
        fn: e => math.sin(e)
    },
    cos: {
        reg: /(?<!\w)cos\([\+\-*/.()^\d]+\)(?!\w)/gi,
        fn: e => math.cos(e)
    },
    tan: {
        reg: /(?<!\w)tan\([\+\-*/.()^\d]+\)(?!\w)/gi,
        fn: e => math.tan(e)
    },
    asin: {
        reg: /(?<!\w)asin\([\+\-*/.()^\d]+\)(?!\w)/gi,
        fn: e => math.asin(e)
    },
    acos: {
        reg: /(?<!\w)acos\([\+\-*/.()^\d]+\)(?!\w)/gi,
        fn: e => math.acos(e)
    },
    atan: {
        reg: /(?<!\w)atan\([\+\-*/.()^\d]+\)(?!\w)/gi,
        fn: e => math.atan(e)
    },
    atan2: {
        reg: /(?<!\w)atan2\([\+\-*/.()^\d]+\)(?!\w)/gi,
        fn: e => math.atan2(e)
    },
    sinh: {
        reg: /(?<!\w)sinh\([\+\-*/.()^\d]+\)(?!\w)/gi,
        fn: e => math.sinh(e)
    },
    cosh: {
        reg: /(?<!\w)cosh\([\+\-*/.()^\d]+\)(?!\w)/gi,
        fn: e => math.cosh(e)
    },
    tanh: {
        reg: /(?<!\w)tanh\([\+\-*/.()^\d]+\)(?!\w)/gi,
        fn: e => math.tanh(e)
    },
    atan: {
        reg: /(?<!\w)atan\([\+\-*/.()^\d]+\)(?!\w)/gi,
        fn: e => math.atan(e)
    },
    log10: {
        reg: /(?<!\w)log10\([\+\-*/.()^\d]+\)(?!\w)/gi,
        fn: e => math.log10(e)
    },
    pow: {
        reg: /(?<!\w)pow\([\+\-*/.()^\d]+\)(?!\w)/gi,
        fn: e => math.pow(e)
    },
    ceil: {
        reg: /(?<!\w)ceil\([\+\-*/.()^\d]+\)(?!\w)/gi,
        fn: e => math.ceil(e)
    },
    floor: {
        reg: /(?<!\w)floor\([\+\-*/.()^\d]+\)(?!\w)/gi,
        fn: e => math.floor(e)
    },
    hypot: {
        reg: /(?<!\w)hypot\([\+\-*/.()^\d]+\)(?!\w)/gi,
        fn: e => math.hypot(e)
    },
}



// const isNum = i => typeof i == 'number' || (typeof i == 'string' && /^[\d.]+$/.test(i) && !isNaN(+i));
const isNum = i => typeof i == 'number' || (typeof i == 'string' && !!i.trim().length && !isNaN(+i));
const isArr = (e, is = isNum) => Array.isArray(e) ||
    (typeof e == 'string' && /^[\[].*[\]]$/.test(e) && e.slice(1, -1).split(',').every(i => is(i)));
const isObj = e => typeof e === 'object' && !isArr(e) && e !== null;
const isEquObj = (e, f) => {
    if (!isObj(e) || !isObj(f)) {
        return false;
    }
    e = objV2S(e), f = objV2S(f)
    const ke = Object.keys(e), kf = Object.keys(f);
    if (ke.length !== kf.length) {
        return false;
    }
    for (const i of ke) {
        if (e[i] !== f[i]) {
            return false;
        }
    }
    return true;
};
const isExp = i => {
    if (!new RegExp(`^[\\d+\\-*/.${Object.keys(keywordObj)
        // .filter(j => keywordObj[j].value)
        .map(j => `(${j})`).join('')}\]+$`, 'gi').test(i)) return false;
    for (const key of Object.keys(keywordObj).filter(e => keywordObj[e].reg.test(i))) {
        i = i.replaceAll(keywordObj[key].reg, keywordObj[key].value)
    }
    // console.log('👷', i)
    try {
        if (typeof evaluate(i) !== 'number') return false;
    } catch {
        return false
    }
    return true
};
// const testkey = 'exp'
// console.log('👡', isExp(testkey), typeof evaluate(testkey))
// console.log('👩‍❤️‍💋‍👩', isNum(' '))
// console.log('👩‍❤️‍💋‍👩', isNum(' 12  31'))
// console.log('👩‍❤️‍💋‍👩', isNum({}))
// console.log('👩‍❤️‍💋‍👩', isNum([]))
// console.log('👩‍❤️‍💋‍👩', isNum(undefined))
// console.log('👩‍❤️‍💋‍👩', isNum(null))
// console.log('👩‍❤️‍💋‍👩', isNum(''))
// console.log('👩‍❤️‍💋‍👩', isNum(12.3))
// console.log('👩‍❤️‍💋‍👩', isNum('012.3'))
// console.log('🥽', isArr('[1, 1]'))










/**
 * 根据路径获取深层对象值
 * @param {string} str 深层对象路径
 * @param {any} value 值
 * @returns 获取到的值
 */
const getMObjVal = (str, obj = {}) => {
    // 路径分割成数组
    const path = str.split('/');
    try {
        return path.reduce((a, b) => a[b], obj)
    } catch (error) {
        return undefined
    }
}
/**
 * 根据路径设置深层对象值
 * @param {string} str 深层对象路径
 * @param {any} value 值
 * @param {object} obj 深层对象
 */
const setMObjVal = (str, value, obj = {}) => {
    const _obj = obj
    // 路径分割成数组
    const path = str.split('/');
    for (let j = 0; j < path.length - 1; j++) {
        if (!obj[path[j]]) {
            obj[path[j]] = {}
        }
        obj = obj[path[j]]
    }
    obj[path.at(-1)] = value
    return _obj
}



function objV2S(obj) {
    for (const key in obj) {
        // console.log('👨‍👨‍👧', key, obj[key], typeof obj[key])
        const valid = ['string', 'boolean'].includes(typeof obj[key]) ||
            (typeof obj[key] === 'number' && !isNaN(obj[key]))
        if (typeof obj[key] === 'object' && obj[key] !== null) {
            objV2S(obj[key])
        } else if (valid) {
            obj[key] += ''
        } else {
            delete obj[key]
        }
    }
    return obj
}

/**
 * 对象值转换为数字
 * @param {object} obj 待处理对象（内部不能处理转化为字符串的数组）
 * @returns 返回处理完的对象
 */
function objV2N(obj) {
    for (const key in obj) {
        if (typeof obj[key] === 'object' && obj[key] !== null) {
            objV2N(obj[key])
        } else if (isNum(obj[key])) {
            obj[key] = +obj[key]
        } else {
            delete obj[key]
        }
    }
    return obj
}





let stencilPre = true;
let stencilArr = {};
let searchFn = (cell, keyword, groupName, stencil) => {
    let g = stencil.groups[groupName]
    // console.log(cell, keyword, groupName, stencil, g);
    let gAll = g.querySelectorAll('.x6-cell.x6-node.x6-node-immovable')
    let gFou = g.querySelectorAll('.x6-cell.x6-node.x6-node-immovable.unmatched')
    let g1 = gAll.length
    let g2 = gFou.length
    let gv = g1 > g2 + 1 ? g1 - g2 - 1 : 1


    let { options: { layoutOptions: { columns } } } = stencil
    gv = Math.ceil(gv / columns)
    $(g).css({ '--trh': 50 * gv + 20 + 'px' })


    if (groupName == 'stencilDbl') {
        let gList = [...gAll].filter(i => ![...gFou].includes(i))
        console.log(cell, keyword, groupName, stencil, g, gList);
        if (keyword) {
            $(g).css({ display: 'initial' })
        } else {
            $(g).css({ display: 'none' })
        }
    }
    if (keyword) {
        let stencilCur = cell.attr('text/text')?.toLowerCase().includes(keyword.toLowerCase())
        // console.log(groupName, stencilPre, stencilCur, g1, g2);
        if (!Array.isArray(stencilArr[groupName]) || stencilPre == undefined) {
            stencilArr[groupName] = []
        }
        stencilArr[groupName].push(stencilCur)

        if (stencilCur == undefined && stencilArr[groupName].find(i => i)) {
            stencilPre = stencilCur
            return true;
        }

        stencilPre = stencilCur
        if (!stencilCur) return false;
    }

    g.classList.value.includes('collapsed') && $(g).removeClass('collapsed')
    stencilPre = true
    return true
}







const scopeMenu = [
    {
        title: '文件(F)',
        item: [
            {
                title: '仿真开始时打开(T)',
            },
            {
                title: '输入端口个数(U)',
                // item: [
                //     { title: '1' },
                //     { title: '2' },
                //     { title: '3' },
                // ],
                fn(...params) {
                    params[0].value = false
                    const { cell, data } = params.at(-1)
                    ElMessageBox.prompt('请输入端口个数', '输入端口个数', {
                        confirmButtonText: '确定',
                        cancelButtonText: '取消',
                        inputPattern: /^[1-9]\d*$/,
                        inputErrorMessage: '请输入正整数'
                    }).then(({ value }) => {
                        console.log(value);
                        data.Inputs = +value
                        cell.removePorts(cell.getPortsByGroup('left'))
                        cell.addPorts(Array(+value).fill(pi.default))
                        cell.size(cell.size().width, +value * 20)
                    })
                    console.log(params, cell);
                },
                d: 1
            },
            {
                title: '复制到剪贴板(Y)',
                d: 1,
                tip: 'Ctrl+C'
            },
            {
                title: '打印(P)...',
                tip: 'Ctrl+P'
            },
            {
                title: '打印预览(V)',
            },
            {
                title: '打印到图窗(R)',
                d: 1
            },
            {
                title: '关闭(C)',
                tip: 'Ctrl+W'
            },
            {
                title: '关闭所有Scope窗口(A)',
            },
        ]
    },
    {
        title: '工具(T)',
        item: [
            {
                title: '放大(Z)',
            },
            {
                title: '缩放X(X)',
            },
            {
                title: '缩放Y(Y)',
            },
            {
                title: '缩小(O)',
            },
            {
                title: '平移(P)',
                d: 1
            },
            {
                title: '坐标区缩放(S)',
                item: [
                    { title: '1' },
                    { title: '2' },
                ],
                d: 1
            },
            {
                title: '触发器(T)',
                d: 1
            },
            {
                title: '测量(M)',
                item: [
                    { title: '1' },
                    { title: '2' },
                ],
            },
        ]
    },
    {
        title: '视图(V)',
        item: [
            {
                title: '布局(L)...',
            },
            {
                title: '配置属性(C)...',
            },
            {
                title: '样式(Y)...',
            },
            {
                title: '图例(E)',
                d: 1
            },
            {
                title: '前置所有Scope窗口(F)',
                d: 1,
                tip: 'Ctrl+F'
            },
            {
                title: '工具栏(T)',
            },
            {
                title: '状态栏(S)',
                d: 1
            },
            {
                title: '突出显示Simulink 模块(H)',
                tip: 'Ctrl+L'
            },
            {
                title: '读取视图数据',
                fn(e, scope) {
                    scope.setOption({ tooltip: { show: e.value } })
                }
            }
        ]
    },
    {
        title: '仿真(I)',
        item: [
            {
                title: '步退(B)',
            },
            {
                title: '运行(已调速)(R)',
                tip: 'Ctrl+T'
            },
            {
                title: '步进(F)',
            },
            {
                title: '停止(T)',
            },
            {
                title: '逐步仿真选项(E)',
                d: 1
            },
            {
                title: 'Simulink快照(H)',
            },
        ]
    },
    {
        title: '帮助(H)',
        item: [
            {
                title: 'Scope帮助(H)',
            },
            {
                title: 'Simulink 帮助(S)',
                d: 1
            },
            {
                title: '键盘命令帮助(K)',
                d: 1
            },
            {
                title: 'Simulink示例(E)',
                d: 1
            },
            {
                title: '关于Simulink(A)',
            }
        ]
    },
]


const scopeOption = {
    color: ['#ffff09', '#0ba0ff', '#ff6924', '#64d50b', '#b844ff',
        '#06ffff', '#ff0ba7'],
    animation: 'auto',
    animationDuration: 1000,
    animationDurationUpdate: 500,
    animationEasing: 'cubicInOut',
    animationEasingUpdate: 'cubicInOut',
    animationThreshold: 2000,
    grid: {
        containLabel: true,
        top: 20,
        left: 5,
        right: 25,
        bottom: 5
    },
    textStyle: {
        color: '#fff',
        fontSize: 12
    },
    xAxis: [
        {
            hideOverlap: true,
            axisLabel: {
                width: 32,
                ellipsis: '',
                overflow: 'truncate'
            },
            axisTick: {
                inside: true
            },
            axisLine: {
                onZero: false,
                lineStyle: {
                    color: '#afafaf'
                }
            },
            splitLine: {
                lineStyle: {
                    color: '#afafaf66'
                }
            },
            splitNumber: 10
        },
        {
            // offset: 2,
            alignTicks: true,
            axisTick: {
                inside: true
            },
            axisLine: {
                onZero: false,
                lineStyle: {
                    color: '#afafaf'
                }
            },
            axisLabel: {
                show: false
            },
            splitLine: {
                lineStyle: {
                    color: '#afafaf66'
                }
            }
        }
    ],
    yAxis: [
        {
            hideOverlap: true,
            axisLabel: {
                width: 32,
                ellipsis: '',
                overflow: 'truncate'
            },
            axisTick: {
                inside: true,
            },
            axisLine: {
                lineStyle: {
                    color: '#afafaf',
                }
            },
            splitLine: {
                lineStyle: {
                    color: '#afafaf66'
                }
            },
            splitNumber: 10
        },
        {
            alignTicks: true,
            axisTick: {
                inside: true
            },
            axisLine: {
                onZero: false,
                lineStyle: {
                    color: '#afafaf'
                }
            },
            axisLabel: {
                show: false
            },
            splitLine: {
                lineStyle: {
                    color: '#afafaf66'
                }
            }
        }
    ],
    tooltip: {
        show: false,
        trigger: 'axis',
        className: 'scopeTooltip',
        // alwaysShowContent: true,
        formatter: function (params) {
            // console.log(params);
            let str = `<div>x : ${params[0].axisValue}</div>`;
            params.forEach((i, j) => {
                str += !i.value[j + 1] ? '' :
                    `<div>${i.marker}y${j + 1} : ${i.value[j + 1]}</div>`;
            })
            return str;
        },
        axisPointer: {
            type: 'line',
            snap: false,
            label: {
                show: false
            }
        }
    },
    dataZoom: [
        {
            show: true,
            type: 'inside',
            filterMode: 'none',
            xAxisIndex: [0],
            startValue: -20,
            endValue: 20
        },
        {
            show: true,
            type: 'inside',
            filterMode: 'none',
            yAxisIndex: [0],
            startValue: -20,
            endValue: 20
        }
    ]
}











const amplify = [
    {
        tagName: 'path',
        attrs: {
            stroke: 'transparent',
            strokeWidth: 300,
        },
    },
]
const downArrow = {
    transform: 'scale(0.015) translate(-510,-850)',
    d: 'M104.704 338.752a64 64 0 0 1 90.496 0l316.8 316.8 316.8-316.8a64 64 0 0 1 90.496 90.496L557.248 791.296a64 64 0 0 1-90.496 0L104.704 429.248a64 64 0 0 1 0-90.496z',
    magnet: true,
    style: {
        // visibility: 'hidden',
    }
}
const defaultInput = {
    group: 'left',
    markup: amplify,
    attrs: {
        path: downArrow,
    },
}
const pi = {
    default: defaultInput,
    cheng: {
        ...defaultInput,
        attrs: {
            path: downArrow,
            // path: { ...downArrow, fill: '#f44336' },
            text: {
                text: '×',
                value: '*'
            },
        },
    },
    chu: {
        ...defaultInput,
        attrs: {
            path: downArrow,
            // path: { ...downArrow, fill: '#2196f3' },
            text: {
                text: '÷',
                value: '/'
            }
        },
    },
    jia: {
        ...defaultInput,
        attrs: {
            path: downArrow,
            // path: { ...downArrow, fill: '#f44336' },
            text: {
                text: '+',
            },
        },
    },
    jian: {
        ...defaultInput,
        attrs: {
            path: downArrow,
            // path: { ...downArrow, fill: '#2196f3' },
            text: {
                text: '-'
            }
        },
        label: {
            position: {
                args: {
                    x: 9
                }
            }
        }
    },
    jiac: {
        ...defaultInput,
        group: 'ellipse',
        attrs: {
            path: downArrow,
            // path: { ...downArrow, fill: '#f44336' },
            text: {
                text: '+'
            }
        },
    },
    jianc: {
        ...defaultInput,
        group: 'ellipse',
        attrs: {
            path: downArrow,
            // path: { ...downArrow, fill: '#2196f3' },
            text: {
                text: '-',
            }
        },
    },
    deng: {
        ...defaultInput,
        type: 'chu',
        group: 'right',
        attrs: {
            path: downArrow,
            // path: { ...downArrow, fill: '#4caf50' },
            text: {
                text: null
                // text: '='
            }
        },
    },
}
const ports = {
    groups: {
        left: {
            position: {
                args: {
                    angle: -90,
                },
            },
            label: {
                position: {
                    name: 'right',
                    args: {
                        x: 5
                    }
                }
            }
        },
        right: {
            position: {
                name: 'right',
                args: {
                    dx: 8,
                    angle: -90,
                }
            },
            label: {
                position: {
                    args: {
                        y: -2
                    }
                }
            }
        },
        ellipse: {
            position: {
                name: 'ellipse',
                args: {
                    start: -90,
                    step: -20,
                    compensateRotate: true
                }
            },
            label: {
                position: {
                    name: 'right',
                    args: {
                        x: 7
                    }
                }
            }
        },
    },
}
const data = {
    nodes: [
        {
            id: 'node',
            shape: 'circle',
            x: 800,
            y: 340,
            width: 40,
            height: 40,
            label: 'Sum',
            markup: [
                {
                    tagName: 'circle',
                    selector: 'body',
                },
                {
                    tagName: 'image',
                    selector: 'img',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                // body 是选择器名称，选中的是 rect 元素
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                    rx: 6,
                    ry: 6,
                },
                // img: {
                //     'xlink:href':
                //         'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/antv.png',
                //     width: 16,
                //     height: 16,
                //     x: 12,
                //     y: 12,
                // },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports, items: [
                    pi.jiac,
                    pi.jiac,
                    pi.deng
                ]
            }
        },
        {
            id: 'node1',
            shape: 'rect',
            x: 540,
            y: 340,
            width: 40,
            height: 40,
            label: 'Product',
            attrs: {
                // body 是选择器名称，选中的是 rect 元素
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    {
                        ...defaultInput,
                        attrs: {
                            path: downArrow,
                            // path: { ...downArrow, fill: '#f44336' },
                            text: {
                                text: '×',
                                fontSize: 10,
                                x: -5
                            },
                        },
                    },
                    {
                        ...defaultInput,
                        attrs: {
                            path: downArrow,
                            // path: { ...downArrow, fill: '#f44336' },
                            text: {
                                text: '÷',
                                fontSize: 10,
                                x: -5
                            },
                        },
                    },
                    pi.deng,
                ],
            }
        },
        {
            id: 'node2',
            shape: 'rect',
            x: 660,
            y: 480,
            width: 100,
            height: 50,
            label: 'Subsystem',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'image',
                    selector: 'img',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                img: {
                    href: '/Subsystem.png',
                    // 'xlink:href': '/Subsystem.png',
                    refWidth: '97%',
                    refHeight: '98%',
                    x: 1,
                    y: 2,
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            id: 'node3',
            shape: 'polygon',
            x: 340,
            y: 340,
            width: 40,
            height: 40,
            points: '0 0,50 25,0 50',
            label: 'Gain',
            markup: [
                {
                    tagName: 'polygon',
                    selector: 'body',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
                {
                    tagName: 'text',
                    selector: 'data',
                },
            ],
            attrs: {
                // body 是选择器名称，选中的是 rect 元素
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                    rx: 6,
                    ry: 6,
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                },
                data: {
                    text: '1',
                    textVerticalAnchor: 'middle',
                    refX: '40%',
                    refY: '50%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 40,
            height: 40,
            label: 'Constant',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
                {
                    tagName: 'text',
                    selector: 'data',
                },
            ],
            attrs: {
                // body 是选择器名称，选中的是 rect 元素
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                },
                data: {
                    text: '1',
                    textVerticalAnchor: 'middle',
                    refY: '50%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 40,
            height: 40,
            label: 'RelationalOperator',
            // label: 'RalationalOperator',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
                {
                    tagName: 'text',
                    selector: 'data',
                },
            ],
            attrs: {
                // body 是选择器名称，选中的是 rect 元素
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                },
                data: {
                    text: '≤',
                    textVerticalAnchor: 'middle',
                    refY: '50%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 40,
            height: 40,
            label: `Saturation`,
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'image',
                    selector: 'img',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                img: {
                    href: '/img/17.webp',
                    // 'xlink:href': '/img/.webp',
                    refWidth: '97%',
                    refHeight: '98%',
                    x: 1,
                    y: 2,
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 40,
            height: 40,
            label: `RateLimiter`,
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'image',
                    selector: 'img',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                img: {
                    href: '/img/13.webp',
                    // 'xlink:href': '/img/.webp',
                    refWidth: '97%',
                    refHeight: '98%',
                    x: 1,
                    y: 2,
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 50,
            height: 40,
            label: 'PID',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
                {
                    tagName: 'text',
                    selector: 'data',
                },
            ],
            attrs: {
                // body 是选择器名称，选中的是 rect 元素
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                },
                data: {
                    text: 'PID(s)',
                    textVerticalAnchor: 'middle',
                    refY: '50%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 40,
            height: 40,
            label: `DeadZone`,
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'image',
                    selector: 'img',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                img: {
                    href: '/img/11.webp',
                    // 'xlink:href': '/img/.webp',
                    refWidth: '97%',
                    refHeight: '98%',
                    x: 1,
                    y: 2,
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 40,
            height: 40,
            label: `Integrator`,
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'image',
                    selector: 'img',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                img: {
                    href: '/img/58.webp',
                    // 'xlink:href': '/img/.webp',
                    refWidth: '97%',
                    refHeight: '98%',
                    x: 1,
                    y: 2,
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 40,
            height: 40,
            label: `Sqrt`,
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'foreignObject',
                    selector: 'latex',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                latex: {
                    html: '<div style="font-size: 14px;"><span class="katex"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msqrt><mi>u</mi></msqrt></mrow><annotation encoding="application/x-tex">\\sqrt{u}</annotation></semantics></math></span></div>',
                    refX: .5,
                    refY: .5,
                    x: -9,
                    y: -14,
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 40,
            height: 40,
            label: `MinMax`,
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                // {
                //     tagName: 'image',
                //     selector: 'img',
                // },
                {
                    tagName: 'text',
                    selector: 'data',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                // img: {
                //     href: '/img/.webp',
                //     // 'xlink:href': '/img/.webp',
                //     refWidth: '97%',
                //     refHeight: '98%',
                //     x: 1,
                //     y: 2,
                // },
                data: {
                    text: 'min',
                    textVerticalAnchor: 'middle',
                    refY: '50%',
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 40,
            height: 40,
            label: `Sign`,
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'image',
                    selector: 'img',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                img: {
                    href: '/img/48.webp',
                    // 'xlink:href': '/img/.webp',
                    refWidth: '97%',
                    refHeight: '97%',
                    x: 1,
                    y: 1,
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 70,
            height: 70,
            label: 'Lookup_1D',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'image',
                    selector: 'img',
                },
                {
                    tagName: 'text',
                    selector: 'data',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                img: {
                    href: '/img/14.png',
                    // 'xlink:href': '/img/.webp',
                    refWidth: '100%',
                    refHeight: '75%',
                    // x: -10,
                    // y: '.5%',
                    // refX: 20,
                    refY: 12.5,
                },
                data: {
                    text: '1-D T(u)',
                    textVerticalAnchor: 'top',
                    refY: 2,
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 80,
            height: 60,
            label: `Switch`,
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'image',
                    selector: 'img',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                img: {
                    href: '/img/75.png',
                    // 'xlink:href': '/img/.webp',
                    refWidth: '97%',
                    refHeight: '98%',
                    x: 1,
                    y: 2,
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.default,
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 40,
            height: 40,
            label: 'Delay',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'foreignObject',
                    selector: 'latex',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                latex: {
                    html: '<div style="font-size: 16px"><span class="katex"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>z</mi><mrow><mo>−</mo><mn>2</mn></mrow></msup></mrow><annotation encoding="application/x-tex">z^{-2}</annotation></semantics></math></span></div>',
                    refX: .5,
                    refY: .5,
                    x: -14,
                    y: -12,
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 40,
            height: 40,
            label: 'Scope',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'image',
                    selector: 'img',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                img: {
                    href: '/img/44.webp',
                    refWidth: '97%',
                    refHeight: '98%',
                    x: 1,
                    y: 2,
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 7,
            height: 40,
            label: 'Mux',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#000',
                    fill: '#000',
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 7,
            height: 40,
            label: 'Demux',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#000',
                    fill: '#000',
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.deng,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 55,
            height: 40,
            label: 'TransferFcn',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'foreignObject',
                    selector: 'latex',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                latex: {
                    html: '<div style="font-size: 12px"><span class="katex"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mstyle displaystyle="true" scriptlevel="0"><mfrac><mn>1</mn><mrow><mi>s</mi><mo>+</mo><mn>1</mn></mrow></mfrac></mstyle></mrow><annotation encoding="application/x-tex">\dfrac{1}{s+1}</annotation></semantics></math></span></div>',
                    htmlW: 40,
                    latex: '\\dfrac{1}{s+1}',
                    refX: .5,
                    refY: .5,
                    x: -16.5,
                    // x: 12,
                    y: -16,
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 60,
            height: 40,
            label: 'Filter_1st',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'foreignObject',
                    selector: 'latex',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                latex: {
                    html: '<div style="font-size: 14px"><span class="katex"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mstyle displaystyle="true" scriptlevel="0"><mfrac><mi>a</mi><mrow><mi>s</mi><mo>+</mo><mi>a</mi></mrow></mfrac></mstyle></mrow><annotation encoding="application/x-tex">\dfrac{a}{s+a}</annotation></semantics></math></span></div>',
                    refX: .5,
                    refY: .5,
                    x: -20,
                    y: -16,
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 120,
            height: 60,
            label: 'Filter_2nd',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'foreignObject',
                    selector: 'latex',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                latex: {
                    html: '<div style="font-size: 14px"><span class="katex"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mstyle displaystyle="true" scriptlevel="0"><mfrac><msup><mi>ω</mi><mn>2</mn></msup><mrow><msup><mi>s</mi><mn>2</mn></msup><mo>+</mo><mn>2</mn><mi>ξ</mi><mi>ω</mi><mi>s</mi><mo>+</mo><msup><mi>ω</mi><mn>2</mn></msup></mrow></mfrac></mstyle></mrow><annotation encoding="application/x-tex">\\dfrac{\\omega^{2}}{s^{2}+2\\xi\omega s+\\omega^{2}}</annotation></semantics></math></span></div>',
                    refX: .5,
                    refY: .5,
                    x: -56,
                    y: -20,
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 40,
            height: 40,
            label: 'SineWave',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'image',
                    selector: 'img',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                img: {
                    href: '/img/4.webp',
                    refWidth: '100%',
                    refHeight: '100%',
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 60,
            height: 50,
            label: 'DllModel',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'foreignObject',
                    selector: 'url',
                },
                {
                    tagName: 'foreignObject',
                    selector: 'name',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                url: {
                    html: `
                    <div>
                        ./libfuelsys.dll
                    </div>`,
                    width: 60,
                    class: 'ellipsis',
                    refX: '50%',
                    refY: '50%',
                    x: -30,
                    y: -23
                },
                name: {
                    html: `
                    <div>
                        Sheet1
                    </div>`,
                    width: 60,
                    class: 'ellipsis',
                    refX: '50%',
                    refY: '50%',
                    x: -30,
                    y: -3
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 60,
            height: 50,
            label: 'FMU_Model',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'foreignObject',
                    selector: 'url',
                },
                {
                    tagName: 'foreignObject',
                    selector: 'name',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
                {
                    tagName: 'image',
                    selector: 'img',
                }
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                url: {
                    html: `
                    <div>
                        Unspecified FMU
                    </div>`,
                    width: 60,
                    class: 'ellipsis',
                    refX: '50%',
                    refY: '50%',
                    x: -30,
                    y: -23
                },
                name: {
                    html: `
                    <div>
                        Import
                    </div>`,
                    width: 60,
                    class: 'ellipsis',
                    refX: '50%',
                    refY: '50%',
                    x: -30,
                    y: -3
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                },
                img: {
                    // href: '/img/4.webp',
                    refWidth: '100%',
                    refHeight: '100%',
                },
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'polygon',
            x: 340,
            y: 340,
            width: 60,
            height: 40,
            points: '0 0,40 0,50 25,40 50,0 50',
            label: 'From',
            markup: [
                {
                    tagName: 'polygon',
                    selector: 'body',
                },
                {
                    tagName: 'text',
                    selector: 'data',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                data: {
                    text: '[A]',
                    textVerticalAnchor: 'top',
                    refY: '50%',
                    x: -4,
                    y: -6
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.deng,
                ],
            }
        },
        {
            shape: 'polygon',
            x: 340,
            y: 340,
            width: 60,
            height: 40,
            points: '0 25,10 0,50 0,50 50,10 50',
            label: 'Goto',
            markup: [
                {
                    tagName: 'polygon',
                    selector: 'body',
                },
                {
                    tagName: 'text',
                    selector: 'data',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                data: {
                    text: '[A]',
                    textVerticalAnchor: 'top',
                    refY: '50%',
                    x: 4,
                    y: -6
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                ],
            }
        },
        {
            shape: 'rect',
            x: 660,
            y: 180,
            width: 40,
            height: 20,
            label: 'In',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'text',
                    selector: 'data',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                    rx: 10,
                    ry: 10,
                },
                data: {
                    text: '1',
                    refY: '50%',
                    y: -6
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.deng,
                ]
            }
        },
        {
            shape: 'rect',
            x: 860,
            y: 180,
            width: 40,
            height: 20,
            label: 'Out',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'text',
                    selector: 'data',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                    rx: 10,
                    ry: 10,
                },
                data: {
                    text: '1',
                    refY: '50%',
                    y: -6
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default
                ]
            }
        },
        {
            shape: 'rect',
            // x: 540,
            // y: 240,
            width: 100,
            height: 50,
            label: 'Acc_Control',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
                {
                    tagName: 'text',
                    selector: 'data',
                },
            ],
            attrs: {
                // body 是选择器名称，选中的是 rect 元素
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                },
                data: {
                    text: 'ACC/DEC',
                    textVerticalAnchor: 'middle',
                    refY: '50%',
                    x: 10
                }
            },
            ports: {
                ...ports,
                items: [
                    {
                        ...defaultInput,
                        attrs: {
                            path: downArrow,
                            // path: { ...downArrow, fill: '#f44336' },
                            text: {
                                text: 'x',
                                fontSize: 10,
                                x: -5,
                            },
                        },
                    },
                    {
                        ...defaultInput,
                        attrs: {
                            path: downArrow,
                            // path: { ...downArrow, fill: '#f44336' },
                            text: {
                                text: 'wf0',
                                fontSize: 10,
                                x: -5,
                            },
                        },
                    },
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 60,
            height: 60,
            label: 'GainSchedule',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
                {
                    tagName: 'text',
                    selector: 'data',
                },
            ],
            attrs: {
                // body 是选择器名称，选中的是 rect 元素
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                },
                data: {
                    text: 'GS(z)',
                    textVerticalAnchor: 'middle',
                    refY: '50%',
                }
            },
            ports: {
                ...ports,
                items: [
                    {
                        ...defaultInput,
                        attrs: {
                            path: downArrow,
                            // path: { ...downArrow, fill: '#f44336' },
                            text: {
                                text: 'e',
                                fontSize: 10,
                                x: -5,
                            },
                        },
                    },
                    {
                        ...defaultInput,
                        attrs: {
                            path: downArrow,
                            // path: { ...downArrow, fill: '#f44336' },
                            text: {
                                text: 'x',
                                fontSize: 10,
                                x: -5,
                            },
                        },
                    },
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 40,
            height: 40,
            label: 'Step',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'image',
                    selector: 'img',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                // body 是选择器名称，选中的是 rect 元素
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                img: {
                    href: '/img/64.webp',
                    refWidth: '100%',
                    refHeight: '80%',
                    refY: '10%',
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 40,
            height: 40,
            label: 'Abs',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'image',
                    selector: 'img',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                // body 是选择器名称，选中的是 rect 元素
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                img: {
                    href: '/img/7.png',
                    refWidth: '100%',
                    refHeight: '100%',
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 40,
            height: 40,
            label: 'Math',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                {
                    tagName: 'foreignObject',
                    selector: 'latex',
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                latex: {
                    html: '<div style="font-size: 14px;"><span class="katex"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>e</mi><mi>u</mi></msup></mrow><annotation encoding="application/x-tex">e^{u}</annotation></semantics></math></span></div>',
                    refX: .5,
                    refY: .5,
                    x: -9,
                    y: -12,
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.deng,
                ],
            }
        },
        {
            shape: 'rect',
            x: 540,
            y: 240,
            width: 40,
            height: 40,
            label: 'ManualSwitch',
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body',
                },
                // {
                //     tagName: 'image',
                //     selector: 'img',
                // },
                {
                    tagName: 'polyline',
                    selector: 'switch'
                },
                {
                    tagName: 'circle',
                    selector: 'c1'
                },
                {
                    tagName: 'circle',
                    selector: 'c2'
                },
                {
                    tagName: 'circle',
                    selector: 'c3'
                },
                {
                    tagName: 'text',
                    selector: 'label',
                },
            ],
            attrs: {
                // body 是选择器名称，选中的是 rect 元素
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                },
                // img: {
                //     href: '/img/63.webp',
                //     refWidth: '100%',
                //     refHeight: '100%',
                // },
                switch: {
                    refPoints: '40,40 40,0 40,20 30,20 10,10 0,10 0,0 0,40 0,30 2,30',
                    // refPoints: '40,0 40,40 40,20 30,20 10,30 0,30 0,40 0,0 0,10 2,10',
                    fill: 'none',
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                },
                c1: {
                    refCx: .15,
                    refCy: .25,
                    refR: .1,
                    fill: '#FFF',
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                },
                c2: {
                    refCx: .15,
                    refCy: .75,
                    refR: '10%',
                    fill: '#FFF',
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                },
                c3: {
                    refCx: .85,
                    refCy: .5,
                    refR: '10%',
                    fill: '#FFF',
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                },
                text: {
                    textVerticalAnchor: 'top',
                    refY: '110%',
                }
            },
            ports: {
                ...ports,
                items: [
                    pi.default,
                    pi.default,
                    pi.deng,
                    // { ...pi.default, MS: 1 },
                    // { ...pi.default, MS: 2 },
                    // { ...pi.deng, MS: 3 },
                ],
            }
        },
    ]
}



function getBranchEdge(point, zhuS, zhuT, pCell, ppix, cCell, cpix, status) {
    console.log(point, zhuS, zhuT, pCell, ppix, cCell, cpix);
    if (zhuT.x) {
        point = zhuT
    }
    let arr = [
        // 起始端到断点
        {
            source: zhuS, target: point,
            attrs: {
                line: {
                    xu: Object.values(point).join(' '),
                    targetMarker: {
                        name: 'circle',
                        r: 3,
                        cx: -1
                    },
                }
            }
        },
        // 断点到结束端
        {
            source: point, target: zhuT,
            attrs: {
                line: {
                    xu: Object.values(point).join(' '),
                    // sourceMarker: {
                    //     name: 'circle',
                    //     r: 3,
                    //     cx: -1
                    // },
                    targetMarker: {
                        name: 'classic',
                        size: 16,
                        offset: 4
                        // d: 'M .5 -8 16 0 .5 8 4 1 -14 1 -14 -1 4 -1 Z',
                    }
                }
            }
        },
        // 断点到结束端（子线）
        {
            source: point,
            // source: { cell: cCell, anchor: 'orth' },
            target: { cell: status ? cCell : pCell, port: status ? cpix : ppix },
            attrs: {
                line: {
                    xu: Object.values(point).join(' '),
                    mainS: { cell: !status ? cCell : pCell, port: !status ? cpix : ppix },
                    // sourceMarker: {
                    //     name: 'circle',
                    //     r: 3,
                    //     cx: -1
                    // },
                    targetMarker: {
                        name: 'classic',
                        size: 16,
                        offset: 4
                        // d: 'M .5 -8 16 0 .5 8 4 1 -14 1 -14 -1 4 -1 Z',
                    }
                }
            }
        }
    ]
    if (zhuT.x) {
        arr.splice(1, 1)
    }
    return arr
}

function changeModelData(args, cell, x, y) {
    let [graph, dialogObj, route, router, breadcrumb, nodeTem, katex] = args
    // console.log(cell, x, y);
    let {
        id, uid, uuid, shape, port, ts, store,
        store: {
            data: {
                position: { x: px, y: py },
                size: { width: w, height: h }
            }
        },
        attrs: { text, data }
    } = cell


    let isArea =
        px + w / 2 - 6 < x && px + w / 2 + 6 > x && py + h / 2 - 6 < y && y < py + h / 2 + 6
    // return console.log(isArea, x, px + (w / 2), y, py + (h / 2));
    let con = {
        illustrate: {},
        config: {},
        data: {},
        // is: false,
        w: null,
        cell: cell,
        hidden: false
    }

    con.illustrate.id = text.text
    con.illustrate.type = ts
    con.illustrate.title = text.text
    con.illustrate.name = ts
    let changeObj = {
        Sum() {
            //  = shape
            // con.data.Inputs = port.ports.map((i) => i.attrs.text.text).join('')
            con.illustrate.content = `对输入执行加法或减法。请指定下列选项之一:a)字符向量，其中包含+或-表示每个输入端口，包含|表示端口之间的分隔符(例如 +- ++)b)标量，>=1，指定要求和的输入端口的数量。当只有一个输入端口时，在所有维度或指定维度上对元素执行加法或减法。`
        },
        Product() {
            con.w = 600
            // con.data.type = shape
            // con.data.list = port.ports.map((i) => i.attrs.text.text).join('')
            con.illustrate.content = `乘法或除法输入。选择按元素或矩阵乘积，并为每个输入端口指定下列选项之一:
 a) * 或 /。例如，**/* 执行运算 'u1*u2/u3*u4'。
 b) 一个标量值，用来指定要相乘的输入端口数。例如，2 执行运算 'u1*u2'。

如果只有一个输入端口并且 "乘法" 参数设置为 "按元素(.*)"，则单个 * 或 / 使用指定的运算缩减输入信号。但是，如果 "乘法" 参数设置为 "矩阵(*)"，则单个 * 会导致模块原样输出矩阵，单个 / 会导致模块输出逆矩阵。`
        },
        Subsystem() {
            //     // breadcrumb里arr为页面实时数据，breadcrumb里carr为页面历史数据
            //     let _arr = [...(route.params.children || '').split('>'), text.text].filter((i) => i)
            //     if (_arr.length == 1) _arr.unshift('untitled')
            //     let _url = _arr.join('>')
            //     // let _url = '/s/' + _arr.join('>')

            //     let _obj = {
            //         name: _arr.at(-1),
            //         level: _arr.length,
            //         path: _url,
            //     }
            //     if (breadcrumb.carr.at(-1).path == _url) breadcrumb.carr.pop()
            //     breadcrumb.carr.at(-1).cells = graph.getCells()
            //     breadcrumb.carr.push(_obj)

            //     let _lb = objV2S({
            //         id: cell.id,
            //         level: _arr.length,
            //         parentId: breadcrumb.lb[_arr.length - 2]?.id
            //     })
            //     // breadcrumb.lb.push(_lb)

            //     console.log(route, breadcrumb, _arr, _url, _obj, _lb)

            //     let nodes = [
            //         {
            //             id: 'node1',
            //             shape: 'rect',
            //             x: 660,
            //             y: 180,
            //             width: 50,
            //             height: 20,
            //             label: '1',
            //             attrs: {
            //                 body: {
            //                     stroke: '#8f8f8f',
            //                     strokeWidth: 1,
            //                     fill: '#fff',
            //                     rx: 10,
            //                     ry: 10
            //                 }
            //             },
            //             ports: {
            //                 ...ports,
            //                 items: [
            //                     {
            //                         ...pi.deng,
            //                         id: 'output'
            //                     }
            //                 ]
            //             }
            //         },
            //         {
            //             id: 'node2',
            //             shape: 'rect',
            //             x: 860,
            //             y: 180,
            //             width: 50,
            //             height: 20,
            //             label: '2',
            //             attrs: {
            //                 body: {
            //                     stroke: '#8f8f8f',
            //                     strokeWidth: 1,
            //                     fill: '#fff',
            //                     rx: 10,
            //                     ry: 10
            //                 }
            //             },
            //             ports: {
            //                 ...ports,
            //                 items: [
            //                     {
            //                         ...pi.default,
            //                         id: 'input'
            //                     }
            //                 ]
            //             }
            //         }
            //     ]

            //     graph.clearCells()
            //     graph.addNodes(nodes)



            con.hidden = true
            //     router.push(_url)
        },
        Gain() {
            con.illustrate.content = `模块将输入乘以一个常里值(增益)。输入和增益可以是标量、向量或矩阵。`
            // con.illustrate.content = `按元素增益(y= K.*u)或矩阵增益(y=K*u或y= u*K)。`
        },
        Constant() {
            con.illustrate.content = `输出由"常量值"参数指定的常量。如果"常量值"是向量并且"将向量参数解释为一维向量"处于启用状态，则将常量值视为一维数组。否则，输出其维数与常量值相同的矩阵。`
        },
        DeadZone() {
            con.illustrate.content = `输入位于死区内时输出零。超出死区时，按起始值或结束值对输入信号进行偏移。`
        },
        PID() {
            con.w = 800
            con.illustrate.name = `PID 1dof (mask) (link)`
            con.illustrate.content = `此模块实现连续和离散时间 PID 控制算法，并包括高级功能，如抗饱和、外部重置和信号跟踪。您可以使用 '调节...' 按钮自动调节 PID 增益(需要 Simulink Control Design)。`
            con.config = {
                controller: 0,
                form: 1,
                radio: 1,
                source: 1
            }

        },
        Lookup_1D() {
            con.w = 800
            con.illustrate.name = 'Lookup Table (n-D)'
            con.illustrate.content =
                '执行 n 维插值表查找，包括索引搜索。该表是函数的 N 个变量的采样表示形式。断点集将输入值与表中的位置相关联。第一个维度对应于顶部(或左侧)输入端口。'
            con.config = {
                dimension: 1,
                dataSet: true,
                breakPointSet: true,
                arr: [
                    { source: false, value: 'tanh([-5:5])' },
                    { source: false, value: '[-5:5]' }
                ],
                dataType: [
                    { label: '表数据', mode: '继承' },
                    { label: '', mode: '继承' },
                    { label: '区间比', mode: '继承' },
                    { label: '中间结果', mode: '继承' },
                    { label: '输出', mode: '继承' }
                ]
            }
        },
        TransferFcn() {
            // let latex = '<div style="font-size: 12px">'
            //     + katex.renderToString('\\dfrac{1}{s+2}', {
            //         output: 'mathml'
            //     }) + '</div>'
            // // console.log(latex, cell);
            // cell.attr('latex/html', latex)
            con.illustrate.content = `分子系数可以是向量或矩阵表达式。分母系数必须为向量。输出宽度等于分子系数中的行数。您应按照 s 的幂的降序来指定系数。

                                        '参数可调性' 控制分子和分母系数的运行时可调性级别。
                                        '自动': 允许 Simulink 选择最合适的可调性级别。
                                        '优化': 可调性已针对性能进行优化。
                                        '无约束': 跨仿真目标的可调性无约束。`
        },
        Math() {
            if (isArea) {
                let latex = (e) =>
                    '<div style="font-size: 14px;">' +
                    katex.renderToString(e, {
                        output: 'mathml'
                    }) +
                    '</div>'
                // console.log(latex('e^{u}'), cell);
                // cell.attr('latex/html', latex)
                let _arr = [
                    { label: 'exp', value: 'e^{u}', w: '-9' },
                    { label: 'log', value: '\\ln u', w: '-12' },
                    { label: '2^u', value: '2^{u}', w: '-8.5' },
                    { label: '10^u', value: '10^{u}', w: '-13' },
                    { label: 'log10', value: '{\\scriptsize \\log_{10}{u}}', w: '-16.5' },
                    { label: 'mag...e^2', value: '{\\small \\left | u \\right | ^{2}}', w: '-23.5' },
                    { label: 'square', value: 'u^{2}', w: '-9' },
                    { label: 'pow', value: 'u^{v}', w: '-9' },
                    { label: 'conj', value: '\\bar{u}', w: '-5' },
                    { label: 'reciprocal', value: '\\frac{1}{u}', w: '-4.5' },
                    { label: 'hypot', value: '{\\small hypot}', w: '-20' },
                    { label: 'rem', value: 'rem', w: '-15' },
                    { label: 'mod', value: 'mod', w: '-16.5' },
                    { label: 'transpose', value: 'u^{T}', w: '-9' },
                    { label: 'hermitian', value: 'u^{H}', w: '-10' }
                ].map(i => ({ ...i, value: latex(i.value) }))
                let { x: pageX, y: pageY } = graph.localToPage(x, y)
                nodeTem.attrs = {
                    data: {
                        is: true,
                        x: pageX - 30,
                        y: pageY - 15,
                        w: 60,
                        fn(val) {
                            cell.attr({
                                latex: {
                                    html: val,
                                    x: _arr.find((i) => i.value == val).w
                                }
                            })
                            nodeTem.attrs.data.is = false
                        },
                        value: cell.attr('latex/html'),
                        options: _arr
                    }
                }
                return
            }

            con.illustrate.content =
                '数学函数，包括对数、指数、幂和模数函数。当函数有多个参数时，第一个参数对应于顶部(或左侧)输入端口。'
        },
        ManualSwitch() {
            con.hidden = true
        },
        From() {
            let mark = (data.value || data.text).slice(1, -1)
            let GotoArr = graph.getNodes().filter((i) => i.ts == 'Goto')

            if (isArea) {
                let { x: pageX, y: pageY } = graph.localToPage(x, y)
                nodeTem.attrs = {
                    data: {
                        is: true,
                        x: pageX - 30,
                        y: pageY - 15,
                        w: 60,
                        fn(val) {
                            const name = compareW(cell, val)
                            dialogObj[uuid].data.GotoTag = name
                            // dialogObj[text.text].data.GotoTag = name
                            nodeTem.attrs.data.is = false
                        },
                        value: mark,
                        options: GotoArr.map((i) => ({
                            value: (i.attrs.data.value || i.attrs.data.text).slice(1, -1)
                        }))
                    }
                }
                con.hidden = true
            }

            // graph.addNode({ ...data.nodes[0], id: 'from1' })
            // let e = graph.translate()
            // console.log(e);

            con.config = {
                mark: mark,
                Goto: {
                    name: null,
                    to() {
                        let { cell } = dialogObj[uuid].data
                        // let { cell } = dialogObj[text.text].data
                        // console.log(dialogObj[text.text]);
                        // console.log(cell);
                        graph.centerCell(cell)
                        cell.attr('body/fill', '#00d1d1')
                        cell.attr('body/stroke', '#0000cc')
                        dialogObj[uuid].is = false
                        // dialogObj[text.text].is = false
                    }
                },
                GotoArr: GotoArr,
                upDate() {
                    let GotoArr = graph.getNodes().filter((i) => i.ts == 'Goto')
                    dialogObj[uuid].data.GotoArr = GotoArr
                    // dialogObj[text.text].data.GotoArr = GotoArr
                }
            }
            con.illustrate.content =
                "用指定的标记从 Goto 模块接收信号。如果标记在 Goto 模块中定义为 '限定作用域'，则必须使用 Goto Tag Visibility 模块来定义标记的可见性。在 '更新图' 后，模块图标显示所选标记名称(局部标记用方括号 [] 括起来，限定作用域标记名称用花括号 {} 括起来)。"

        },
        Goto() {
            let mark = (data.value || data.text).slice(1, -1)

            if (isArea) {
                let { x: pageX, y: pageY } = graph.localToPage(x, y)
                nodeTem.attrs = {
                    data: {
                        is: true,
                        x: pageX - 30,
                        y: pageY - 15,
                        w: 60,
                        fn(val) {
                            const name = compareW(cell, val)
                            dialogObj[uuid].data.GotoTag = name
                            // dialogObj[text.text].data.GotoTag = name
                            nodeTem.attrs.data.is = false
                        },
                        value: mark,
                        input: true
                    }
                }
                con.hidden = true
            }
            // let from = graph.getCellById('from1')
            // graph.centerCell(from)

            let getFromArr = (mark) => {
                return graph
                    .getNodes()
                    .filter((i) => i.ts == 'From' && i.attrs.data.text.slice(1, -1) == mark)
                    .map((i) => ({
                        node: i,
                        fn() {
                            graph.centerCell(i)
                            i.attr('body/fill', '#00d1d1')
                            i.attr('body/stroke', '#0000cc')
                            // i.attr('body/filter', {
                            //     name: 'highlight',
                            //     args: {
                            //         color: '#66C2FF',
                            //         width: 3,
                            //     }
                            // })
                            dialogObj[uuid].is = false
                            // dialogObj[text.text].is = false
                        }
                    }))
            }
            con.config = {
                mark: mark,
                FromArr: getFromArr(mark),
                upDate(mark) {
                    dialogObj[uuid].data.FromArr = getFromArr(mark)
                    // dialogObj[text.text].data.FromArr = getFromArr(mark)
                }
            }
            con.illustrate.content =
                "向具有指定标记的 From 模块发送信号。如果标记可见性是 '限定作用域'，则必须使用 Goto Tag Visibility 模块来定义标记的可见性。模块图标显示所选标记名称(局部标记用方括号 [] 括起来，限定作用域标记名称用花括号 {} 括起来)。"
            console.log(con);
        },
        In() {
            con.illustrate.name = 'Inport'
            con.illustrate.content =
                "为子系统或模型提供输入端口。\n对于触发子系统，'通过延迟外部信号锁存输入' 生成在前一时间步的子系统输入值。\n对于函数调用子系统，启用 '针对函数调用子系统输出的反馈信号锁存输入' 可防止此子系统的输入值在其执行过程中发生变化。\n其他参数可用于显式指定输入信号属性。"
        },
        Out() {
            con.illustrate.name = 'Outport'
            con.illustrate.content =
                "为子系统或模型提供输出端口。'禁用时的输出' 和 '初始输出' 参数仅适用于条件执行子系统。当禁用条件执行子系统时，输出或者保持在最后一个值，或者设置为 '初始输出'。"
        },
        Acc_Control() {
            con.w = 800
            con.illustrate.name = `PID 1dof (mask) (link)`
            con.illustrate.content = `此模块实现连续和离散时间 PID 控制算法，并包括高级功能，如抗饱和、外部重置和信号跟踪。您可以使用 '调节...' 按钮自动调节 PID 增益(需要 Simulink Control Design)。`
            con.config = {
                controller: 0,
                form: 1,
                radio: 1,
                source: 1
            }

        },
        Filter_1st() {
            // let latex = '<div style="font-size: 14px">'
            //     + katex.renderToString('\\dfrac{a}{s+a}', {
            //         output: 'mathml'
            //     }) + '</div>'
            // // console.log(latex, cell);
            // cell.attr('latex/html', latex)
            con.illustrate.content =
                "分子系数可以是向量或矩阵表达式。分母系数必须为向量。输出宽度等于分子系数中的行数。您应按照 s 的幂的降序来指定系数。变量为'a'"
        },
        Filter_2nd() {
            // let latex = '<div style="font-size: 14px">'
            //     + katex.renderToString('\\dfrac{\\omega^{2}}{s^{2}+2\\xi\\omega s+\\omega^{2}}', {
            //         output: 'mathml'
            //     }) + '</div>'
            // // console.log(latex, cell);
            // cell.attr('latex/html', latex)
            con.illustrate.content = '模式1：变量为阻尼比和角速度 模式2：变量为a和b'
        },
        Integrator() {
            con.illustrate.content = '输入信号的连续时间积分。'
            con.config = {
                ExternalResetOption: {
                    "null": ["无", null],
                    "rising": ["上升沿", "↑"],
                    "falling": ["下降沿", "↓"],
                    "either": ["任一沿", "↕"],
                    "level": ["级别", "_¯_"],
                    "level hold": ["级别保持", " "],
                },
                InitialConditionSourceOption: {
                    internal: ['内部', null],
                    external: ['外部', 'x0']
                }
            }
        },
        GainSchedule() {
            con.w = 800
            con.illustrate.name = `PID 1dof (mask) (link)`
            con.illustrate.content = `此模块实现连续和离散时间 PID 控制算法，并包括高级功能，如抗饱和、外部重置和信号跟踪。您可以使用 '调节...' 按钮自动调节 PID 增益(需要 Simulink Control Design)。`
            con.config = {
                controller: 0,
                form: 1,
                radio: 1,
                source: 1
            }

        },
        DllModel() {
            con.illustrate.title = 'Dll'
            con.illustrate.name = 'DLL文件接口调用'
            con.illustrate.content = '使用 DLL 实现模块。请打开 DLL 文件路径。'
            con.config.tag = cell.uuid
        },
        FMU_Model() {
            con.illustrate.title = 'FMU'
            con.illustrate.name = 'FMU文件接口调用'
            con.illustrate.content = '使用 FMU 实现模块。请打开 FMU 文件路径。'
            con.config.tag = cell.uuid
        },
        SineWave() {
            con.illustrate.content = `输出正弦波:

                                        O(t) = Amp*Sin(Freq*t+相位) + 偏置

                                        正弦类型确定使用的计算方法。这两种类型的参数通过以下方式相关联:

                                        每个周期的采样数 = 2*pi / (频率 * 采样时间)

                                        偏移采样数 = 相位 * 每周期采样数 / (2*pi)

                                        如果由于长时间运行(例如，绝对时间溢出)而出现数值问题，请使用基于采样的正弦类型。`
        },
        Step() {
            con.illustrate.content = '输出一个步长。'
        },
        Abs() {
            con.illustrate.content = 'y = |u|'
        },
        Delay() {
            // // 得到公式
            // let latex = '<div style="font-size: 16px">'
            //     + katex.renderToString('z^{-3}', {
            //         output: 'mathml'
            //     }) + '</div>'
            // // console.log(latex, cell);
            // cell.attr('latex/html', latex)
            con.w = 600
            con.illustrate.content = '将输入信号延迟指定数量的采样。'
        },
        MinMax() {
            if (isArea) {
                let _arr = [{ value: 'min' }, { value: 'max' }]
                let { x: pageX, y: pageY } = graph.localToPage(x, y)
                nodeTem.attrs = {
                    data: {
                        is: true,
                        x: pageX - 30,
                        y: pageY - 15,
                        w: 60,
                        fn(val) {
                            cell.attr({
                                data: {
                                    text: val
                                    // x: _arr.find(i => i.value == val).w
                                }
                            })
                            nodeTem.attrs.data.is = false
                        },
                        value: cell.attr('data/text'),
                        options: _arr
                    }
                }
                return
            }

            con.w = 600
            con.illustrate.content =
                '输出输入的最小值或最大值。对于单一输入，运算符应用于整个输入向量。对于多个输入，运算符应用于所有这些输入。'
        },
        RelationalOperator() {
            // RalationalOperator() {
            if (isArea) {
                let _arr = [
                    { value: '==', value1: '＝＝' },
                    { value: '~=', value1: '≠' },
                    { value: '<', value1: '＜' },
                    { value: '<=', value1: '≤' },
                    { value: '>=', value1: '≥' },
                    { value: '>', value1: '＞' },
                    { value: 'isInf', value1: 'isinf' },
                    { value: 'isNaN', value1: 'isnan' },
                    { value: 'isFinite', value1: 'isfinite' }
                ]
                let { x: pageX, y: pageY } = graph.localToPage(x, y)
                nodeTem.attrs = {
                    data: {
                        is: true,
                        x: pageX - 30,
                        y: pageY - 15,
                        w: 60,
                        fn(val) {
                            cell.attr({
                                data: {
                                    text: val
                                }
                            })
                            let con = dialogObj[uuid]
                            // let con = dialogObj[text.text]
                            con.data.Operator = con.config.OperatorData[val]
                            nodeTem.attrs.data.is = false
                        },
                        value: cell.attr('data/text'),
                        options: _arr
                    }
                }
                con.hidden = true
            }
            con.config = {
                OperatorOption: {
                    "==": "Equal",
                    "~=": "DoesnotEqual",
                    "<": "Lessthan",
                    "<=": "LessthanorEqual",
                    ">=": "GreaterthanorEqual",
                    ">": "Greaterthan",
                    "isInf": "isInf",
                    "isNaN": "isNaN",
                    "isFinite": "isFinite",
                }
            }
            con.w = 600
            con.illustrate.content =
                '将所选关系运算符应用于输入并输出结果。顶部(或左侧)输入对应于第一个操作数。'
        },
        RateLimiter() {
            con.illustrate.content = '限制信号的上升沿和下降沿速率。'
        },
        Saturation() {
            con.w = 600
            con.illustrate.content = '限制信号的上升沿和下降沿速率。'
        },
        Sign() {
            con.illustrate.name = 'Signum'
            con.illustrate.content =
                '对于实数输入，输出 1 表示正输入，-1 表示负输入，0 表示 0 输入。对于复数浮点输入，输出遵循 sign(u) = u ./ abs(u)'
        },
        Sqrt() {
            if (isArea) {
                let latex = (e) =>
                    '<div style="font-size: 14px;">' +
                    katex.renderToString(e, {
                        output: 'mathml'
                    }) +
                    '</div>'
                let _arr = [
                    { label: 'sqrt', value: '\\sqrt{u}', w: '-11.5' },
                    {
                        label: 'signedSqrt',
                        value: '{\\tiny \\pm \\sqrt{\\left | u \\right | }}',
                        w: '-16'
                    },
                    { label: 'rSqrt', value: '\\frac{1}{\\sqrt{u}}', w: '-9' }
                    // { label: 'exp', value: 'e^{u}', w: '-9' },
                ].map((i) => ({ ...i, value: latex(i.value) }))
                let { x: pageX, y: pageY } = graph.localToPage(x, y)
                nodeTem.attrs = {
                    data: {
                        is: true,
                        x: pageX - 30,
                        y: pageY - 15,
                        w: 60,
                        fn(val) {
                            cell.attr({
                                latex: {
                                    html: val,
                                    x: _arr.find((i) => i.value == val).w
                                }
                            })
                            console.log(val)
                            // console.log(document.getElementById('mathLatex').scrollWidth);
                            nodeTem.attrs.data.is = false
                        },
                        value: cell.attr('latex/html'),
                        options: _arr
                    }
                }
                return
            }

            con.illustrate.content =
                '将所选关系运算符应用于输入并输出结果。顶部(或左侧)输入对应于第一个操作数。'
        },
        Scope() {
            con.data.ScopeID = cell['-ID'] ? 'System_' + (+cell['-ID'] + 1) : 'System_' + (+uid + 1)
            if (!dialogObj[uuid].data && cell?.['-Ports']) {
                con.data.Inputs = cell['-Ports'].slice(1, -1).split(',')[0]
            } else {
                con.data.Inputs = 1
            }
            // con.hidden = true
            console.log('🙎‍♀️', con, cell, dialogObj, dialogObj[uuid])
        },
        Demux() {
            con.illustrate.content = '将向量信号拆分为标量或更小的向量。'
        },
        Mux() {
            con.illustrate.content =
                '将具有相同数据类型和复/实性的标量或向量信号合并为一个虚拟向量。此模块不串联信号。'
        },
        Switch() {
            con.w = 600
            con.illustrate.content =
                '当输入 2 满足所选条件时，输入 1 通过；否则，输入 3 通过。输入从上到下(或从左到右)进行编号。第一个和第三个输入端口是数据端口，第二个输入端口是控制端口。控制端口 2 的条件是 u2 >= 阈值，u2 > 阈值或 u2 ~= 0。'
        }
    }

    const defaultObj = {
        Constant: {
            Value: 1,
            VectorParams1D: "on",
            SampleTime: "Inf",
        },
        SineWave: {
            SineType: "TimeBase",
            Time: "UseSimulationTime",
            Amplitude: 1,
            Bias: 0,
            Frequency: 1,
            Phase: 0,
            SamplesPerPeriod: 10,
            VectorParams1D: "on",
        },
        Step: {
            Time: 1,
            Before: 0,
            After: 1,
            SampleTime: 0,
            VectorParams1D: "on",
            ZeroCross: "on",
        },
        Sign: {
            ZeroCross: "on"
        },
        Sum: {
            Inputs: "++"
        },
        Abs: {
            ZeroCross: "on"
        },
        Delay: {
            DelayLength: 1,
            InitialLength: 0,
            InputProcessing: "BaseInSample",
            UseCircularBuffer: "off",
            ShowEnablePort: "off",
            ExternalReset: "null",
            SampleTime: -1,
        },
        DeadZone: {
            UpperValue: 0.5,
            LowerValue: -0.5,
            SaturateOnIntegerOverflow: "on",
            LinearizeAsGain: "on",
            ZeroCross: "on",
        },
        Gain: {
            Gain: 1
        },
        Lookup_1D: {
            NumberOfTableDimensions: 1,
            X_VEC: "[1, 50, 100]",
            Y_VEC: "[0.01, 0.5, 1]",
            InternalRulePriority: "Speed"
        },
        Math: {
            Operator: "exp"
        },
        MinMax: {
            Function: "Min",
            Inputs: 2,
            ZeroCross: "on",
        },
        Product: {
            Inputs: "**"
        },
        Saturation: {
            UpperValue: 0.5,
            LowerValue: -0.5,
            LinearizeAsGain: "on",
            ZeroCross: "on",
        },
        Sqrt: {
            Operator: "Sqrt"
        },
        RateLimiter: {
            RisingSlewLimit: 1,
            FallingSlewLimit: -1,
            SampleTimeMode: "inherited",
            InitialCondition: 0,
            LinearizeAsGain: "on",
        },
        RelationalOperator: {
            Operator: "Equal",
            ZeroCross: "on",
        },
        Integrator: {
            ExternalReset: "null",
            InitialConditionSource: "internal",
            InitialCondition: 1,
            LimitOutput: "off",
            UpperSaturationLimit: "inf",
            LowerSaturationLimit: "-inf",
            ShowSaturationPort: "off",
            AbsoluteTolerance: "auto",
            IgnoreLimit: "off",
            ZeroCross: "on",
            StateName: "' '",
        },
        TransferFcn: {
            Numerator: "[1]",
            Denominator: "[1, 1]",
            // InitialCondition: 0,
            ParameterTunability: "auto",
            AbsoluteTolerance: "auto",
            ContinuousStateAttributes: "''",
        },
        PID: {
            Controller: "PID",
            P: 1,
            I: 1,
            D: 0,
            UseFilter: "off",
            N: 100,
            LimitOutput: "off",
            InitialConditionForIntegrator: 0,
            InitialConditionForFilter: 0,
            UpperSaturationLimit: "inf",
            LowerSaturationLimit: "-inf",
            IgnoreLimit: "off",
            ZeroCross: "on",
            StateName: "' '",
        },
        GainSchedule: {
            Controller: "PID",
            X_VEC: "[0, 10]",
            P_VEC: "[0, 10]",
            I_VEC: "[0, 0]",
            D_VEC: "[0, 0]",
            UseFilter: "off",
            N: 100,
            LimitOutput: "off",
            InitialConditionForIntegrator: 0,
            InitialConditionForFilter: 0,
            UpperSaturationLimit: "Inf",
            LowerSaturationLimit: "-inf",
            IgnoreLimit: "off",
            ZeroCross: "on",
            StateName: "' '",
        },
        Acc_Control: {
            X_VEC: 1,
            Wf_VEC: 1
        },
        Filter_1st: {
            a: 1,
            InitialCondition: 0,
            TimeStep: -1,
        },
        Filter_2nd: {
            ParameterMode: "Ksi-Omega",
            ksi: 1,
            omega: 1,
            a: 1,
            b: 1,
            InitialCondition: 0,
            TimeStep: -1,
        },
        Filter_RateLimit: {
            a: 1,
            InitialCondition: 0,
            RateUpperValue: 1,
            RateLowerValue: 0,
            TimeStep: -1,
        },
        Switch: {
            Criteria: "u2 GreaterthanorEqual Threshold",
            Threshold: 0,
            ZeroCross: "on",
        },
        ManualSwitch: {
            CurrentSetting: 1
        },
        Mux: {
            Inputs: 2,
            SampleTimeMode: "line",
        },
        Demux: {
            Outputs: 2,
            SampleTimeMode: "line",
        },
        DllModel: {
            Path: "",
            InitialCondition: "[0, 1]",
            InitFunc: "Init",
            OnestepFunc: "Onestep",
            TerminateFunc: "TerminateFunc",
            NumofInput: 4,
            NumofOutput: 10,
            // TimeStep: 0.01,
        },
        FMU_Model: {
            Path: "",
            InitialCondition: [0],
            // TimeStep: 0.01,
        },
        In: {
            Port: 1
        },
        Out: {
            Port: 1
        },
        Goto: {
            GotoTag: "[A]"
        },
        From: {
            GotoTag: "[A]"
        },
        // SubSystem: {
        //     childrenSystem
        // },
    }


    console.log('😮', dialogObj[uuid], con)
    dialogObj[uuid]?.data || (dialogObj[uuid] = { data: defaultObj[ts] })
    Object.keys(changeObj).includes(ts) && changeObj[ts]()
    if (Object.keys(dialogObj).includes(uuid)) {
        console.log('😮', dialogObj[uuid], con)
        let _obj = {
            ...con,
            ...dialogObj[uuid],
        }
        dialogObj[uuid] = _obj
        if (Object.keys(con.config).length) {
            Object.keys(con.config).forEach(e => {
                dialogObj[uuid].config[e] = con.config[e]
            })
        }
        if (Object.keys(con.data).length) {
            Object.keys(con.data).forEach(e => {
                if (!dialogObj[uuid].data) dialogObj[uuid].data = {}
                dialogObj[uuid].data[e] = con.data[e]
            })
        }
        // console.log(con, _obj);
    } else dialogObj[uuid] = con
}

const getLatex = (latexOption, style = {
    fontSize: 12
}) => {
    const xOption = {
        latex: '', option: {
            output: 'mathml'
        }, ...latexOption
    }
    const latex = katex.renderToString(...Object.values(xOption));
    const div = $(document.createElement('div')).css(style).html(latex)


    return div[0].outerHTML
}
/**
 * 节点名称格式化
 * @param cell 节点
 * @param name 要修改的名称
 */
function compareW(cell, name, options = {
    lue: '-T-', url: 'data/text', cunUrl: 'data/value'
}) {
    if (!name) {
        return;
    }
    let { lue, url, cunUrl } = { lue: '-T-', url: 'data/text', cunUrl: 'data/value', ...options },
        res = name;
    console.log('😘', lue, url, cunUrl, options)
    const w = name.length * 12, { size: { width: sx } } = cell.store.data,
        arr = ['From', 'Goto'];
    if (arr.includes(cell.ts)) {
        name = `[${name}]`
    }
    if (options.isLatex) {
        const { htmlW, latex } = name
        let option = {
            html: getLatex({ latex: latex }),
            x: -htmlW / 2 + 2.5
        }
        if (sx < htmlW + 20) {
            option = {
                html: getLatex({ latex: lue }),
                x: -25
            }
        }
        url = 'latex'
        res = option
    }
    if (options.isHtml) {
        const html = $(document.createElement('div')).html(name)
        console.log('😖', html[0].outerHTML)
        // const { htmlW, latex } = name
        // let option = {
        //     html: getLatex({ latex: latex }),
        //     x: -htmlW / 2 + 2.5
        // }
        // if (sx < htmlW + 20) {
        //     option = {
        //         html: getLatex({ latex: lue }),
        //         x: -25
        //     }
        // }
        // cell.attr({ latex: option })
        res = html[0].outerHTML
    }
    if (sx < w) {
        console.log('👩‍🎨', url, res, lue)
        cell.attr(url, lue)
        cell.attr(cunUrl, res)
    } else {
        cell.attr(url, res)
    }
    return res
}


/**
 * 轮询方法,终止条件为返回一个真值
 * @param fn 需要轮询执行的函数
 * @param interval 轮询间隔时间
 * @param timeout 轮询超时时间
 */
function pollFn(fn, options = { interval: 1000, timeout: 60000 }) {
    const { interval, timeout } = { interval: 1000, timeout: 60000, ...options },
        endTime = +new Date() + timeout;
    let poll;
    return new Promise(poll = async (resolve, reject) => {
        if (+new Date() > endTime) {
            // 如果超时则停止轮询
            reject(new Error("轮询超时"));
        } else if (await fn()) {
            // 如果条件满足则停止轮询
            resolve();
        } else {
            // 否则继续轮询
            setTimeout(poll, interval, resolve, reject);
        }
    });
}

const source_json = {
    "System": {
        "config": {
            "Time": "8",
            "stepTime": "0.01"
        },
        "connections": [
            {
                "inNodeId": "6",
                "inPortIndex": "0",
                "outNodeId": "4",
                "outPortIndex": "0"
            },
            {
                "inNodeId": "3",
                "inPortIndex": "0",
                "outNodeId": "0",
                "outPortIndex": "0"
            },
            {
                "inNodeId": "4",
                "inPortIndex": "0",
                "outNodeId": "2",
                "outPortIndex": "0"
            },
            {
                "inNodeId": "5",
                "inPortIndex": "0",
                "outNodeId": "3",
                "outPortIndex": "0"
            },
            {
                "inNodeId": "3",
                "inPortIndex": "1",
                "outNodeId": "1",
                "outPortIndex": "0"
            }
        ],
        "nodes": [
            {
                "-Ports": "[1,0]",
                "-SID": "Scope_5",
                "-NodeType": "Output/Scope",
                "-ID": "5",
                "Commented": "off",
                "internal-data": {
                    "caption": "Scope",
                    "input-port": {
                        "-port": " "
                    },
                    "node-attr": {
                        "attr": [
                            {
                                "-Name": "ScopeID",
                                "-DataType": "STR",
                                "#text": "System_5"
                            },
                            {
                                "-Name": "Inputs",
                                "-DataType": "F64",
                                "#text": "1"
                            }
                        ]
                    },
                    "output-port": {}
                },
                "position": {
                    "x": "-332",
                    "y": "-408"
                },
                "size": {
                    "height": "80",
                    "width": "70"
                }
            },
            {
                "-Ports": "[0,1]",
                "-SID": "SineWave_1",
                "-NodeType": "Input/SineWave",
                "-ID": "1",
                "Commented": "off",
                "internal-data": {
                    "caption": "SineWave",
                    "input-port": {},
                    "node-attr": {
                        "attr": [
                            {
                                "-Name": "SineType",
                                "-DataType": "STR",
                                "#text": "TimeBase"
                            },
                            {
                                "-Name": "Time",
                                "-DataType": "STR",
                                "#text": "UseSimulationTime"
                            },
                            {
                                "-Name": "Amplitude",
                                "-DataType": "F64",
                                "#text": "2"
                            },
                            {
                                "-Name": "Bias",
                                "-DataType": "F64",
                                "#text": "0"
                            },
                            {
                                "-Name": "Frequency",
                                "-DataType": "F64",
                                "#text": "3.14"
                            },
                            {
                                "-Name": "Phase",
                                "-DataType": "F64",
                                "#text": "0"
                            },
                            {
                                "-Name": "Sampletime",
                                "-DataType": "F64",
                                "#text": "-1"
                            },
                            {
                                "-Name": "VectorParams1D",
                                "-DataType": "STR",
                                "#text": "on"
                            }
                        ]
                    },
                    "output-port": {
                        "-port": " "
                    }
                },
                "position": {
                    "x": "-862",
                    "y": "-352"
                },
                "size": {
                    "height": "70",
                    "width": "70"
                }
            },
            {
                "-Ports": "[1,0]",
                "-SID": "Scope_6",
                "-NodeType": "Output/Scope",
                "-ID": "6",
                "Commented": "off",
                "internal-data": {
                    "caption": "Scope",
                    "input-port": {
                        "-port": " "
                    },
                    "node-attr": {
                        "attr": [
                            {
                                "-Name": "ScopeID",
                                "-DataType": "STR",
                                "#text": "System_6"
                            },
                            {
                                "-Name": "Inputs",
                                "-DataType": "F64",
                                "#text": "1"
                            }
                        ]
                    },
                    "output-port": {}
                },
                "position": {
                    "x": "-314",
                    "y": "-228"
                },
                "size": {
                    "height": "80",
                    "width": "70"
                }
            },
            {
                "-Ports": "[0,1]",
                "-SID": "Constant_0",
                "-NodeType": "Input/Constant",
                "-ID": "0",
                "Commented": "off",
                "internal-data": {
                    "caption": "Constant",
                    "input-port": {},
                    "node-attr": {
                        "attr": [
                            {
                                "-Name": "Value",
                                "-DataType": "F64",
                                "#text": "3.14"
                            },
                            {
                                "-Name": "Sampletime",
                                "-DataType": "F64",
                                "#text": "Inf"
                            },
                            {
                                "-Name": "VectorParams1D",
                                "-DataType": "STR",
                                "#text": "on"
                            }
                        ]
                    },
                    "output-port": {
                        "-port": " "
                    }
                },
                "position": {
                    "x": "-874",
                    "y": "-466"
                },
                "size": {
                    "height": "70",
                    "width": "70"
                }
            },
            {
                "-Ports": "[0,1]",
                "-SID": "Step_2",
                "-NodeType": "Input/Step",
                "-ID": "2",
                "Commented": "off",
                "internal-data": {
                    "caption": "Step",
                    "input-port": {},
                    "node-attr": {
                        "attr": [
                            {
                                "-Name": "Time",
                                "-DataType": "F64",
                                "#text": "1"
                            },
                            {
                                "-Name": "Before",
                                "-DataType": "F64",
                                "#text": "2"
                            },
                            {
                                "-Name": "After",
                                "-DataType": "F64",
                                "#text": "5"
                            },
                            {
                                "-Name": "SampleTime",
                                "-DataType": "F64",
                                "#text": "0"
                            },
                            {
                                "-Name": "VectorParams1D",
                                "-DataType": "STR",
                                "#text": "on"
                            },
                            {
                                "-Name": "ZeroCross",
                                "-DataType": "STR",
                                "#text": "on"
                            }
                        ]
                    },
                    "output-port": {
                        "-port": " "
                    }
                },
                "position": {
                    "x": "-889",
                    "y": "-229"
                },
                "size": {
                    "height": "70",
                    "width": "70"
                }
            },
            {
                "-Ports": "[2,1]",
                "-SID": "Subsystem_3",
                "-NodeType": "Subsystem/Subsystem",
                "-ID": "3",
                "Commented": "off",
                "internal-data": {
                    "caption": "Subsystem_1",
                    "input-port": {
                        "-port": "1|2"
                    },
                    "output-port": {
                        "-port": "1"
                    }
                },
                "position": {
                    "x": "-695",
                    "y": "-453"
                },
                "size": {
                    "height": "70",
                    "width": "70"
                },
                "childrenSystem": {
                    "connections": [
                        {
                            "inNodeId": "1",
                            "inPortIndex": "0",
                            "outNodeId": "5",
                            "outPortIndex": "0"
                        },
                        {
                            "inNodeId": "5",
                            "inPortIndex": "0",
                            "outNodeId": "4",
                            "outPortIndex": "0"
                        },
                        {
                            "inNodeId": "4",
                            "inPortIndex": "0",
                            "outNodeId": "0",
                            "outPortIndex": "0"
                        },
                        {
                            "inNodeId": "3",
                            "inPortIndex": "0",
                            "outNodeId": "2",
                            "outPortIndex": "0"
                        },
                        {
                            "inNodeId": "4",
                            "inPortIndex": "1",
                            "outNodeId": "2",
                            "outPortIndex": "0"
                        }
                    ],
                    "nodes": [
                        {
                            "-Ports": "[1,0]",
                            "-SID": "Out_1",
                            "-NodeType": "Subsystem/Out",
                            "-ID": "1",
                            "Commented": "off",
                            "internal-data": {
                                "caption": "Out",
                                "input-port": {
                                    "-port": " "
                                },
                                "node-attr": {
                                    "attr": [
                                        {
                                            "-Name": "Port",
                                            "-DataType": "F64",
                                            "#text": "1"
                                        }
                                    ]
                                },
                                "output-port": {}
                            },
                            "position": {
                                "x": "344",
                                "y": "-86"
                            },
                            "size": {
                                "height": "70",
                                "width": "70"
                            }
                        },
                        {
                            "-Ports": "[0,1]",
                            "-SID": "In_0",
                            "-NodeType": "Subsystem/In",
                            "-ID": "0",
                            "Commented": "off",
                            "internal-data": {
                                "caption": "In",
                                "input-port": {},
                                "node-attr": {
                                    "attr": [
                                        {
                                            "-Name": "Port",
                                            "-DataType": "F64",
                                            "#text": "1"
                                        }
                                    ]
                                },
                                "output-port": {
                                    "-port": " "
                                }
                            },
                            "position": {
                                "x": "-278",
                                "y": "-155"
                            },
                            "size": {
                                "height": "70",
                                "width": "70"
                            }
                        },
                        {
                            "-Ports": "[0,1]",
                            "-SID": "In_2",
                            "-NodeType": "Subsystem/In",
                            "-ID": "2",
                            "Commented": "off",
                            "internal-data": {
                                "caption": "In",
                                "input-port": {},
                                "node-attr": {
                                    "attr": [{
                                        "-Name": "Port",
                                        "-DataType": "F64",
                                        "#text": "2"
                                    }]
                                },
                                "output-port": {
                                    "-port": " "
                                }
                            },
                            "position": {
                                "x": "-275",
                                "y": "-27"
                            },
                            "size": {
                                "height": "70",
                                "width": "70"
                            }
                        },
                        {
                            "-Ports": "[1,0]",
                            "-SID": "Scope_3",
                            "-NodeType": "Output/Scope",
                            "-ID": "3",
                            "Commented": "off",
                            "internal-data": {
                                "caption": "Scope",
                                "input-port": {
                                    "-port": " "
                                },
                                "node-attr": {
                                    "attr": [
                                        {
                                            "-Name": "ScopeID",
                                            "-DataType": "STR",
                                            "#text": "Subsystem_1_3"
                                        },
                                        {
                                            "-Name": "Inputs",
                                            "-DataType": "F64",
                                            "#text": "1"
                                        }
                                    ]
                                },
                                "output-port": {}
                            },
                            "position": {
                                "x": "-89",
                                "y": "44"
                            },
                            "size": {
                                "height": "80",
                                "width": "70"
                            }
                        },
                        {
                            "-Ports": "[1,1]",
                            "-SID": "Gain_5",
                            "-NodeType": "math/Gain",
                            "-ID": "5",
                            "Commented": "off",
                            "internal-data": {
                                "caption": "Gain",
                                "input-port": {
                                    "-port": " "
                                },
                                "node-attr": {
                                    "attr": [{
                                        "-Name": "Gain",
                                        "-DataType": "F64",
                                        "#text": "2"
                                    }]
                                },
                                "output-port": {
                                    "-port": " "
                                }
                            },
                            "position": {
                                "x": "131",
                                "y": "-47"
                            },
                            "size": {
                                "height": "70",
                                "width": "70"
                            }
                        },
                        {
                            "-Ports": "[2,1]",
                            "-SID": "Sum_4",
                            "-NodeType": "math/Sum",
                            "-ID": "4",
                            "Commented": "off",
                            "internal-data": {
                                "caption": "Sum",
                                "input-port": {
                                    "-port": "+|+"
                                },
                                "node-attr": {
                                    "attr": [{
                                        "-Name": "Inputs",
                                        "-DataType": "STR",
                                        "#text": "++"
                                    }]
                                },
                                "output-port": {
                                    "-port": " "
                                }
                            },
                            "position": {
                                "x": "-37",
                                "y": "-92"
                            },
                            "size": {
                                "height": "70",
                                "width": "70"
                            }
                        }
                    ]
                }
            },
            {
                "-Ports": "[1,1]",
                "-SID": "Subsystem_4",
                "-NodeType": "Subsystem/Subsystem",
                "-ID": "4",
                "Commented": "off",
                "internal-data": {
                    "caption": "Subsystem_2",
                    "input-port": {
                        "-port": "1"
                    },
                    "output-port": {
                        "-port": "1"
                    }
                },
                "position": {
                    "x": "-612",
                    "y": "-250"
                },
                "size": {
                    "height": "70",
                    "width": "70"
                },
                "childrenSystem": {
                    "connections": [
                        {
                            "inNodeId": "1",
                            "inPortIndex": "0",
                            "outNodeId": "7",
                            "outPortIndex": "0"
                        },
                        {
                            "inNodeId": "7",
                            "inPortIndex": "1",
                            "outNodeId": "6",
                            "outPortIndex": "0"
                        },
                        {
                            "inNodeId": "7",
                            "inPortIndex": "0",
                            "outNodeId": "0",
                            "outPortIndex": "0"
                        }
                    ],
                    "nodes": [
                        {
                            "-Ports": "[0,1]",
                            "-SID": "In_0",
                            "-NodeType": "Subsystem/In",
                            "-ID": "0",
                            "Commented": "off",
                            "internal-data": {
                                "caption": "In",
                                "input-port": {},
                                "node-attr": {
                                    "attr": [{
                                        "-Name": "Port",
                                        "-DataType": "F64",
                                        "#text": "1"
                                    }]
                                },
                                "output-port": {
                                    "-port": " "
                                }
                            },
                            "position": {
                                "x": "-273",
                                "y": "-73"
                            },
                            "size": {
                                "height": "70",
                                "width": "70"
                            }
                        },
                        {
                            "-Ports": "[2,1]",
                            "-SID": "Integrator_7",
                            "-NodeType": "Control/Integrator",
                            "-ID": "7",
                            "Commented": "off",
                            "internal-data": {
                                "caption": "Integrator",
                                "input-port": {
                                    "-port": "|x0"
                                },
                                "node-attr": {
                                    "attr": [
                                        {
                                            "-Name": "ExternalReset",
                                            "-DataType": "STR",
                                            "#text": "null"
                                        },
                                        {
                                            "-Name": "InitialConditionSource",
                                            "-DataType": "STR",
                                            "#text": "external"
                                        },
                                        {
                                            "-Name": "LimitOutput",
                                            "-DataType": "STR",
                                            "#text": "off"
                                        },
                                        {
                                            "-Name": "ShowSaturationPort",
                                            "-DataType": "STR",
                                            "#text": "off"
                                        },
                                        {
                                            "-Name": "AbsoluteTolerance",
                                            "-DataType": "STR",
                                            "#text": "auto"
                                        },
                                        {
                                            "-Name": "IgnoreLimit",
                                            "-DataType": "STR",
                                            "#text": "off"
                                        },
                                        {
                                            "-Name": "ZeroCross",
                                            "-DataType": "STR",
                                            "#text": "on"
                                        },
                                        {
                                            "-Name": "StateName",
                                            "-DataType": "STR",
                                            "#text": "''"
                                        }
                                    ]
                                },
                                "output-port": {
                                    "-port": " "
                                }
                            },
                            "position": {
                                "x": "-26",
                                "y": "-12"
                            },
                            "size": {
                                "height": "70",
                                "width": "70"
                            }
                        },
                        {
                            "-Ports": "[0,1]",
                            "-SID": "Constant_6",
                            "-NodeType": "Input/Constant",
                            "-ID": "6",
                            "Commented": "off",
                            "internal-data": {
                                "caption": "Constant",
                                "input-port": {},
                                "node-attr": {
                                    "attr": [
                                        {
                                            "-Name": "Value",
                                            "-DataType": "F64",
                                            "#text": "2.5"
                                        },
                                        {
                                            "-Name": "Sampletime",
                                            "-DataType": "F64",
                                            "#text": "Inf"
                                        },
                                        {
                                            "-Name": "VectorParams1D",
                                            "-DataType": "STR",
                                            "#text": "on"
                                        }
                                    ]
                                },
                                "output-port": {
                                    "-port": " "
                                }
                            },
                            "position": {
                                "x": "-282",
                                "y": "59"
                            },
                            "size": {
                                "height": "70",
                                "width": "70"
                            }
                        },
                        {
                            "-Ports": "[1,0]",
                            "-SID": "Out_1",
                            "-NodeType": "Subsystem/Out",
                            "-ID": "1",
                            "Commented": "off",
                            "internal-data": {
                                "caption": "Out",
                                "input-port": {
                                    "-port": " "
                                },
                                "node-attr": {
                                    "attr": [{
                                        "-Name": "Port",
                                        "-DataType": "F64",
                                        "#text": "1"
                                    }]
                                },
                                "output-port": {}
                            },
                            "position": {
                                "x": "209",
                                "y": "-29"
                            },
                            "size": {
                                "height": "70",
                                "width": "70"
                            }
                        }
                    ]
                }
            }
        ]
    }
}

const subSystemDefaultCells = [
    {
        shape: 'rect',
        x: 660,
        y: 180,
        width: 40,
        height: 20,
        label: 'In',
        group: 'Subsystem',
        ts: 'In',
        markup: [
            {
                tagName: 'rect',
                selector: 'body',
            },
            {
                tagName: 'text',
                selector: 'data',
            },
            {
                tagName: 'text',
                selector: 'label',
            },
        ],
        attrs: {
            body: {
                stroke: '#8f8f8f',
                strokeWidth: 1,
                fill: '#fff',
                rx: 10,
                ry: 10,
            },
            data: {
                text: '1',
                refY: '50%',
                y: -6
            },
            text: {
                textVerticalAnchor: 'top',
                refY: '110%',
            }
        },
        ports: {
            ...ports,
            items: [
                pi.deng,
            ]
        }
    },
    {
        shape: 'rect',
        x: 860,
        y: 180,
        width: 40,
        height: 20,
        label: 'Out',
        group: 'Subsystem',
        ts: 'Out',
        markup: [
            {
                tagName: 'rect',
                selector: 'body',
            },
            {
                tagName: 'text',
                selector: 'data',
            },
            {
                tagName: 'text',
                selector: 'label',
            },
        ],
        attrs: {
            body: {
                stroke: '#8f8f8f',
                strokeWidth: 1,
                fill: '#fff',
                rx: 10,
                ry: 10,
            },
            data: {
                text: '1',
                refY: '50%',
                y: -6
            },
            text: {
                textVerticalAnchor: 'top',
                refY: '110%',
            }
        },
        ports: {
            ...ports,
            items: [
                pi.default
            ]
        }
    }
]

/**
 * 设置节点的端口
 * @param {cls} cell 节点
 * @param {number|string|array} inC 输入端数据，可以是数字，字符串，数组
 * @param {number|string|array} outC 输出端数据，可以是数字，字符串，数组
 * @param {'shape'|''} shape 形状
 */
function systemSetPorts(cell, inC, outC, shape) {
    // console.log('🤧', cell, inC, outC, shape)
    if ((isNum(inC) && inC % 1 != 0) || (isNum(outC) && outC % 1 != 0)) {
        console.log('🤧', cell, inC, outC, (isNum(inC) && inC % 1 != 0), (isNum(outC) && outC % 1 != 0))
        return ElMessage.error('输入输出端口数量必须为整数')
    }
    const { width, height } = cell.size();
    let left, right, inN = inC, outN = outC, inArr, outArr, dSet = {
        '+': shape == 'circle' ? pi.jiac : pi.jia,
        '-': shape == 'circle' ? pi.jianc : pi.jian,
        '*': pi.cheng,
        '/': pi.chu,
        '=': pi.deng,
        ' ': pi.default,
        '$': pi.default,
    }, nowLeftPorts = cell.getPortsByGroup('left').length ? cell.getPortsByGroup('left') : cell.getPortsByGroup('ellipse'),
        nowRightPorts = cell.getPortsByGroup('right');
    if (Array.isArray(inC)) {
        inArr = inC;
        inC = inArr.map(() => '$').join('')
    }
    if (Array.isArray(outC)) {
        outArr = outC;
        outC = outArr.map(() => '$').join('')
    }


    // console.log('👨‍💼', nowLeftPorts, nowRightPorts)

    if (typeof inC == 'number') {
        if (nowLeftPorts.length > inN) {
            for (let i = nowLeftPorts.length - 1; i >= inN; i--) {
                cell.removePort('_in_' + i)
                // cell.removePort((cell['-ID'] ?? cell.uid) + '_in_' + i)
            }
        } else if (nowLeftPorts.length < inN) {
            left = Array(inN - nowLeftPorts.length).fill(pi.default).map((i, j) => ({ ...i, id: '_in_' + (j + nowLeftPorts.length) }))
            // left = Array(inN - nowLeftPorts.length).fill(pi.default).map((i, j) => ({ ...i, id: (cell['-ID'] ?? cell.uid) + '_in_' + (j + nowLeftPorts.length) }))
            console.log('😈', left)
            cell.addPorts(left)
        }
    } else {
        inN = inC.length
        if (nowLeftPorts.length > inN) {
            for (let i = nowLeftPorts.length - 1; i >= inN; i--) {
                cell.removePort((cell['-ID'] ?? cell.uid) + '_in_' + i)
            }
        } else if (nowLeftPorts.length < inN) {
            left = inC.split('').slice(nowLeftPorts.length).map((i, j) => ({ ...dSet[i], id: '_in_' + (j + nowLeftPorts.length) }))
            // left = inC.split('').slice(nowLeftPorts.length).map((i, j) => ({ ...dSet[i], id: (cell['-ID'] ?? cell.uid) + '_in_' + (j + nowLeftPorts.length) }))
            console.log('👒', left)
            cell.addPorts(left)
        }
        // console.log('👀', cell)
        inC.split('').forEach((i, j) => {
            let tu = i
            if (i == '$') {
                tu = inArr[j]
                // console.log('🎒', j, inArr, tu)
            }
            cell.portProp('_in_' + j, 'attrs/text', dSet[i].attrs?.text ?? { text: tu })
            // cell.portProp((cell['-ID'] ?? cell.uid) + '_in_' + j, 'attrs/text', dSet[i].attrs?.text ?? { text: tu })
            cell.portProp('_in_' + j, 'attrs/text/fontSize', 10)
        })
    }



    if (typeof outC == 'number') {
        if (nowRightPorts.length > outN) {
            for (let i = nowRightPorts.length - 1; i >= outN; i--) {
                cell.removePort('_out_' + i)
                // cell.removePort((cell['-ID'] ?? cell.uid) + '_out_' + i)
            }
        } else if (nowRightPorts.length < outN) {
            right = Array(outN - nowRightPorts.length).fill(pi.deng).map((i, j) => ({ ...i, id: '_out_' + (j + nowRightPorts.length) }))
            // right = Array(outN - nowRightPorts.length).fill(pi.deng).map((i, j) => ({ ...i, id: (cell['-ID'] ?? cell.uid) + '_out_' + (j + nowRightPorts.length) }))
            console.log('💆‍♂️', right)
            cell.addPorts(right)
        }
    } else {
        outN = outC.length
        if (nowRightPorts.length > outN) {
            for (let i = nowRightPorts.length - 1; i >= outN; i--) {
                cell.removePort((cell['-ID'] ?? cell.uid) + '_out_' + i)
            }
        } else if (nowRightPorts.length < outN) {
            right = outC.split('').slice(nowRightPorts.length).map((i, j) => ({
                ...dSet[i], type: 'chu', group: 'right',
                id: '_out_' + (j + nowRightPorts.length)
                // id: (cell['-ID'] ?? cell.uid) + '_out_' + (j + nowRightPorts.length)
            }))
            console.log('👨', right)
            cell.addPorts(right)
        }
        outC.split('').forEach((i, j) => {
            let tu = i
            if (i == '$') {
                tu = outArr[j]
            }
            cell.portProp('_out_' + j, 'attrs/text', dSet[i].attrs?.text ?? { text: tu })
            // cell.portProp((cell['-ID'] ?? cell.uid) + '_out_' + j, 'attrs/text', dSet[i].attrs?.text ?? { text: tu })
            cell.portProp('_out_' + j, 'attrs/text/fontSize', 10)
        })
    }
    // console.log('😍', cell, left, right)
    // cell.removePorts()
    // cell.addPorts(left)
    // cell.addPorts(right)
    cell.size(width, Math.max(height, Math.max(inN, outN) * 20))
}







export {
    stGsW,
    amplify,
    downArrow,
    pi,
    ports,
    data,
    scopeOption,
    scopeMenu,
    searchFn,
    keywordObj,
    getBranchEdge,
    changeModelData,
    pollFn,
    objV2S,
    objV2N,
    isExp,
    isNum,
    isArr,
    isObj,
    isEquObj,
    getLatex,
    compareW,
    source_json,
    subSystemDefaultCells,
    systemSetPorts,
    getMObjVal,
    setMObjVal
}